﻿Imports System
Imports System.IO
Imports System.Net
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Data
Imports System.Windows.Media
Imports System.Windows.Media.Animation
Imports System.Windows.Navigation
Imports System.Data
Imports System.Data.SqlClient
Imports System.Text
Imports System.Threading
Imports Microsoft.VisualBasic
Imports System.ComponentModel
Imports System.Xml
Imports System.Linq
Imports System.Xml.Linq
Imports System.Collections.Generic

Partial Public Class Connection
  Implements INotifyPropertyChanged

	Private WithEvents ConnectBackgroundWorker As BackgroundWorker
	'Private OpenConnectionThread As System.Threading.Thread
  Public _DB As Char
  Private bConnectionsLoaded As Boolean
  Private strWindowsUserName As String
  Private bConnected As Boolean

  Public Property DB() As Char
    Get
      Return _DB
    End Get
    Set(ByVal value As Char)
      _DB = value
    End Set
  End Property

  Public Shared ReadOnly IsConnectedProperty As DependencyProperty = DependencyProperty.Register("IsConnected", _
                                                                                             GetType(Boolean), _
                                                                                             GetType(Connection))
  Public Property IsConnected() As Boolean
    Get
      Return DirectCast(Me.GetValue(IsConnectedProperty), Boolean)
    End Get
    Set(ByVal value As Boolean)
      Me.SetValue(IsConnectedProperty, value)

      If value Then
        Me.cmbServerType.IsEnabled = False
        Me.cmbServerName.IsEnabled = False
        Me.cmbAuthentication.IsEnabled = False
        Me.txtUsername.IsEnabled = False
        Me.txtPassword.IsEnabled = False
      Else
        Me.cmbServerType.IsEnabled = True
        Me.cmbServerName.IsEnabled = True
        Me.cmbAuthentication.IsEnabled = True
        cmbAuthentication_Change()
      End If
    End Set
  End Property

  Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
  Protected Sub NotifyPropertyChanged(ByVal propertyName As String)
    RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
  End Sub

  Public Sub New()
    MyBase.New()

    Me.InitializeComponent()

    strWindowsUserName = Environment.UserDomainName & "\" & Environment.UserName
    txtUsername.Text = strWindowsUserName

    Dim dpdComboBox As DependencyPropertyDescriptor = DependencyPropertyDescriptor.FromProperty(ComboBox.TextProperty, GetType(ComboBox))
    dpdComboBox.AddValueChanged(cmbServerName, AddressOf cmbServerName_Change)
    dpdComboBox.AddValueChanged(cmbAuthentication, AddressOf cmbAuthentication_Change)
  End Sub

  Private Sub MyLoaded() Handles Me.Loaded
    Try
      If Base.docConnections IsNot Nothing Then
        Dim servers As List(Of String) = (From s In Base.docConnections.Root.Elements("Connection").Elements("Server") Select s.Value).ToList
        If servers IsNot Nothing Then
          cmbServerName.ItemsSource = servers
          bConnectionsLoaded = True
        End If
      Else
        cmbServerName.ItemsSource = Nothing
      End If
    Catch ex As Exception
			Base.WriteToConsole(ex.ToString)
    End Try

    cmbServerName_Change()
  End Sub

  Protected Sub cmbServerName_Change()
    If Not btnConnect1 Is Nothing Then
      Try
        If bConnectionsLoaded AndAlso cmbServerName.Text > "" Then
          Dim strAuthentication As String = (From c In Base.docConnections.Root.Elements("Connection") Where c.Element("Server").Value = cmbServerName.Text Select c.Element("Authentication").Value).FirstOrDefault
          If strAuthentication > "" Then
            cmbAuthentication.Text = strAuthentication
          End If

          If Not cmbAuthentication.Text.ToLower = "windows authentication" Then
            Dim strUsername As String = (From c In Base.docConnections.Root.Elements("Connection") Where c.Element("Server").Value = cmbServerName.Text Select c.Element("Username").Value).FirstOrDefault
            If strUsername > "" Then
              txtUsername.Text = strUsername
            End If
          End If
        End If
      Catch ex As Exception
				Base.WriteToConsole(ex.ToString)
      End Try

      btnConnect1.IsEnabled = (cmbServerName.Text > "")
    End If
  End Sub

  Protected Sub cmbAuthentication_Change()
    If Not txtUsername Is Nothing AndAlso Not txtPassword Is Nothing Then
      If cmbAuthentication.Text.ToLower = "windows authentication" Then
        txtUsername.IsEnabled = False
        txtPassword.IsEnabled = False
        txtUsername.Text = strWindowsUserName
      Else
        txtUsername.IsEnabled = True
        txtPassword.IsEnabled = True
        If txtUsername.Text = strWindowsUserName Then
          txtUsername.Text = ""
        End If
      End If
    End If
  End Sub

  Protected Sub btnConnect_Click(ByVal sender As Object, ByVal e As RoutedEventArgs) Handles btnConnect1.Click
    If CStr(btnConnect1.Content) = "Connect" Then
      Dim sbConnection As New StringBuilder
      sbConnection.Append("Data Source=")
      sbConnection.Append(cmbServerName.Text)
      sbConnection.Append(";")

      If cmbAuthentication.Text.ToLower = "windows authentication" Then
        sbConnection.Append("Integrated Security=SSPI;")
      Else
        sbConnection.Append("User Id=")
        sbConnection.Append(txtUsername.Text)
        sbConnection.Append(";Password=")
        sbConnection.Append(txtPassword.Password)
        sbConnection.Append(";")
      End If

      Try
        Base.sqlConn(_DB) = New SqlConnection(sbConnection.ToString)
        lblStatus.Content = "Connecting..."
				btnConnect1.Content = "Cancel"
				ConnectBackgroundWorker = New BackgroundWorker
				ConnectBackgroundWorker.WorkerSupportsCancellation = True
				ConnectBackgroundWorker.RunWorkerAsync()
				'OpenConnectionThread = New Thread(AddressOf OpenConnection)
				'OpenConnectionThread.IsBackground = True
				'OpenConnectionThread.Start()
      Catch ex As Exception
        lblStatus.Content = "Error: cannot connect.  See details below."
				Base.WriteToConsole(ex.ToString)
      End Try
    ElseIf CStr(btnConnect1.Content) = "Disconnect" Then
			If ConnectBackgroundWorker IsNot Nothing AndAlso ConnectBackgroundWorker.IsBusy Then
				ConnectBackgroundWorker.CancelAsync()
			End If

			If Base.sqlConn(_DB) IsNot Nothing AndAlso Base.sqlConn(_DB).State = ConnectionState.Open Then
				If Not Base.sqlConn(CChar("A")).Equals(Base.sqlConn(CChar("B"))) Then
					Base.sqlConn(_DB).Close()
				End If
			End If
			IsConnected = False
			btnConnect1.Content = "Connect"
			lblStatus.Content = ""
		Else
			'OpenConnectionThread.Abort()
			ConnectBackgroundWorker.CancelAsync()
			btnConnect1.Content = "Connect"
			lblStatus.Content = ""
		End If
	End Sub

  Protected Delegate Sub UpdateLabelCallback(ByRef lbl As Label, ByVal value As String)
  Protected Sub UpdateLabel(ByRef lbl As Label, ByVal value As String)
    lbl.Content = value
  End Sub

  Protected Delegate Sub UpdateButtonCallback(ByRef btn As Button, ByVal value As String)
  Protected Sub UpdateButton(ByRef btn As Button, ByVal value As String)
    btn.Content = value
  End Sub

  Protected Delegate Sub SaveConnectionCallback()
  Protected Sub SaveConnection()
    IsConnected = Base.sqlConn(_DB) IsNot Nothing AndAlso Base.sqlConn(_DB).State = ConnectionState.Open
    Base.SaveConnection(cmbServerType.Text, cmbServerName.Text, cmbAuthentication.Text, txtUsername.Text)
	End Sub

	Private Sub OpenConnectionCompleted(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs) Handles ConnectBackgroundWorker.RunWorkerCompleted
		If Not e.Cancelled Then
			If TypeOf e.Result Is Boolean AndAlso DirectCast(e.Result, Boolean) Then
				Dispatcher.Invoke(Windows.Threading.DispatcherPriority.Render, New UpdateButtonCallback(AddressOf Me.UpdateButton), btnConnect1, "Disconnect")
				SaveConnection()
			Else
				Dispatcher.Invoke(Windows.Threading.DispatcherPriority.Render, New UpdateButtonCallback(AddressOf Me.UpdateButton), btnConnect1, "Connect")
			End If
		End If
	End Sub

	Private Sub OpenConnection(ByVal sender As Object, ByVal e As DoWorkEventArgs) Handles ConnectBackgroundWorker.DoWork
		Try
			Base.sqlConn(_DB).Open()
			Dim cmd As New SqlCommand("SELECT SERVERPROPERTY('Edition')", Base.sqlConn(_DB))
			Dim strSqlEdition As String = cmd.ExecuteScalar().ToString

			If Not ConnectBackgroundWorker.CancellationPending Then
				Dispatcher.Invoke(Windows.Threading.DispatcherPriority.Render, New Base.WriteToConsoleCallback(AddressOf Base.WriteToConsole), "SQL Product Version: " & Base.sqlConn(_DB).ServerVersion, False)
				Dispatcher.Invoke(Windows.Threading.DispatcherPriority.Render, New Base.WriteToConsoleCallback(AddressOf Base.WriteToConsole), "SQL Edition: " & strSqlEdition, False)
				Dispatcher.Invoke(Windows.Threading.DispatcherPriority.Render, New UpdateLabelCallback(AddressOf Me.UpdateLabel), lblStatus, "")
			End If

			'If strSqlEdition.ToLower.StartsWith("express edition") OrElse strSqlEdition.ToLower.StartsWith("developer edition") Then
				'Dispatcher.Invoke(Windows.Threading.DispatcherPriority.Render, New UpdateLabelCallback(AddressOf Me.UpdateLabel), lblStatus, "Connected")
				'Dim strConnections As String = File.ReadAllText("connections.txt")
				'Dim strDatabaseServer As String = Base.sqlConn(_DB).WorkstationId
				'If Not strConnections.Contains(strDatabaseServer & vbCrLf) Then
				'  File.AppendAllText("connections.txt" & vbCrLf, strDatabaseServer)
				'End If
			'Else
			'  Base.sqlConn(_DB).Close()
			'  Dispatcher.Invoke(Windows.Threading.DispatcherPriority.Render, New UpdateLabelCallback(AddressOf Me.UpdateLabel), lblStatus, "Cannot connect.  This version of Data Comparisons can only connect to Express and Developer editions of Microsoft SQL Server.")
			'End If
		Catch taex As ThreadAbortException
			' do nothing
		Catch ex As Exception
			If Not ConnectBackgroundWorker.CancellationPending Then
				Dispatcher.Invoke(Windows.Threading.DispatcherPriority.Render, New UpdateLabelCallback(AddressOf Me.UpdateLabel), lblStatus, ex.Message)
				Dispatcher.Invoke(Windows.Threading.DispatcherPriority.Render, New Base.WriteToConsoleCallback(AddressOf Base.WriteToConsole), ex.ToString, False)
			End If
		Finally
			e.Result = Base.sqlConn(_DB) IsNot Nothing AndAlso Base.sqlConn(_DB).State = ConnectionState.Open
			'If Base.sqlConn(_DB) IsNot Nothing AndAlso Base.sqlConn(_DB).State = ConnectionState.Open Then
			'	Dispatcher.Invoke(Windows.Threading.DispatcherPriority.Render, New UpdateButtonCallback(AddressOf Me.UpdateButton), btnConnect1, "Disconnect")
			'Else
			'	Dispatcher.Invoke(Windows.Threading.DispatcherPriority.Render, New UpdateButtonCallback(AddressOf Me.UpdateButton), btnConnect1, "Connect")
			'End If
		End Try
	End Sub
End Class
